package com.ubxtech.balance.util;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ubxtech.balance.dto.ServiceInstanceGreyDTO;
import com.ubxtech.balance.dto.ServiceInstanceWebsocketDTO;
import com.ubxtech.core.context.ContextConstants;
import com.ubxtech.core.exception.RRException;
import com.ubxtech.core.hashring.ConsistentHashingVirtualNode;
import com.ubxtech.core.hashring.ServiceNode;
import com.ubxtech.core.utils.GrayVersionUtil;
import com.ubxtech.core.utils.StrPool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Victor.Xiao
 * @since 2023-12-09 14:45
 **/
@Slf4j
public class ServiceInstanceUtil {

    /**
     * 分析出有版本号的实例,独立方法,以便其他地方也能使用
     * @author Victor.Xiao
     * @since 2023-12-09 15:18
     * @param instances instances
    * @param reqVersion reqVersion
     * @return com.ubxtech.balance.dto.ServiceInstanceGreyDTO
    */
    public static ServiceInstanceGreyDTO analysisGreyInstance(List<ServiceInstance> instances, String reqVersion) {
        ServiceInstanceGreyDTO serviceInstanceGreyDTO = new ServiceInstanceGreyDTO();
        //匹配的实例
        List<ServiceInstance> instancesFilter = new ArrayList<>();
        //version为空或者为all的实例,目的是如果没有带版本号,其中有服务带了版本号,则不调用
        List<ServiceInstance> emptyVersionInstancesFilter = new ArrayList<>();
        // 遍历可以实例元数据，若匹配则返回此实例
        for (ServiceInstance instance : instances) {
            Map<String, String> metadata = instance.getMetadata();
            //参考 region-zone-version
            String serverVersion = MapUtil.getStr(metadata, ContextConstants.HEADER_GRAY_VERSION_NAME);
            if (GrayVersionUtil.compareGrayVersion(serverVersion, reqVersion)) {
                if (log.isDebugEnabled()) {
                    log.debug("gray request match success :{} {}", reqVersion, instance);
                }
                instancesFilter.add(instance);
            }
            //为空或者为all的实例
            if (StrUtil.isBlank(serverVersion) || StrUtil.equals(serverVersion, StrPool.GRAY_ALL)) {
                emptyVersionInstancesFilter.add(instance);
            }
        }
        serviceInstanceGreyDTO.setInstancesAll(instances);
        serviceInstanceGreyDTO.setInstancesFilter(instancesFilter);
        serviceInstanceGreyDTO.setEmptyVersionInstancesFilter(emptyVersionInstancesFilter);
        return serviceInstanceGreyDTO;
    }


    /**
     * websocket转发规则
     * @author Victor.Xiao
     * @since 2023-12-09 15:18
     * @param instances instances
     * @param reqVersion reqVersion
     * @return com.ubxtech.balance.dto.ServiceInstanceGreyDTO
     */
    public static ServiceInstanceWebsocketDTO analysisWebsocketInstance(List<ServiceInstance> allInstances, String userId, ConsistentHashingVirtualNode consistentHashingVirtualNode) {
        //所有配置了id的服务
        Map<String, ServiceInstance> serviceIdMap = new HashMap<>();
        for (ServiceInstance allInstance : allInstances) {
            String serviceId = getServiceId(allInstance);
            //有可能没有配置serviceId,需要过滤掉
            if (StrUtil.isNotBlank(serviceId)) {
                serviceIdMap.put(serviceId, allInstance);
            }
        }
        //只存了有serviceId的
        ServiceNode serviceNode = consistentHashingVirtualNode.getServiceNode(userId);
        if (serviceNode == null) {
            log.error("socket服务不存在,所有socket的key:{},userId:{}", serviceIdMap.keySet(),userId);
            throw new RRException("socket服务不存在");
        }
        //分配的服务id
        String serviceId = serviceNode.getServiceId();
        //找到对应的ServiceInstance,先匹配有版本好的
        ServiceInstance serviceInstance = serviceIdMap.get(serviceId);
        if (serviceInstance == null) {
            log.error("找不到对应的socket服务,所有socket的key:{},userId:{},serviceId:{},serviceNode:{}", serviceIdMap.keySet(),userId,serviceId,serviceNode);
            log.error("找不到对应的socket服务,当前hash环:{}", JSONObject.toJSONString(consistentHashingVirtualNode.getVirtualNodes()));
            throw new RRException("找不到对应的socket服务");
        }
        ServiceInstanceWebsocketDTO serviceInstanceWebsocketDTO = new ServiceInstanceWebsocketDTO();
        serviceInstanceWebsocketDTO.setServiceNode(serviceNode);
        serviceInstanceWebsocketDTO.setServiceInstance(serviceInstance);
        return serviceInstanceWebsocketDTO;
    }



    /**
     * 直接根据serviceId匹配对应的serviceInstance
     * @author Victor.Xiao
     * @since 2023-12-11 17:00
     * @param allInstances allInstances
     * @param serviceIdTarget serviceIdTarget
     * @return org.springframework.cloud.client.ServiceInstance
    */
    public static ServiceInstance getInstanceByServiceId(List<ServiceInstance> allInstances, String serviceIdTarget) {
        for (ServiceInstance instance : allInstances) {
            String serviceId = getServiceId(instance);
            //有可能没有配置serviceId,需要过滤掉
            if (StrUtil.isNotBlank(serviceId) && serviceId.equalsIgnoreCase(serviceIdTarget)) {
                return instance;
            }
        }
        return null;
    }

    /**
     * 处理服务id
     * @author Victor.Xiao
     * @since 2023-12-12 10:04
     * @param serviceInstance serviceInstance
     * @return java.lang.String
    */
    public static String getServiceId(ServiceInstance serviceInstance) {
        //元数据里面的值
        String serviceId = serviceInstance.getMetadata().get(ContextConstants.METADATA_SERVICE_ID);
        //实例id
        if (StrUtil.isBlank(serviceId)) {
            serviceId = serviceInstance.getInstanceId();
        }
        //返回port加端口
        if (StrUtil.isBlank(serviceId)) {
            serviceId = serviceInstance.getHost() + ":" + serviceInstance.getPort();
        }
        return serviceId;
    }

    /**
     * 处理nacos中的com.alibaba.nacos.api.naming.pojo.Instance处理方式和ServiceInstance一致
     * @author Victor.Xiao
     * @since 2023-12-12 09:58
     * @param serviceInstance serviceInstance
     * @return java.lang.String
    */
    public static String getServiceId(Object serviceInstance) {
        if (!serviceInstance.getClass().getName().equals("com.alibaba.nacos.api.naming.pojo.Instance")) {
            return "";
        }
        String json = JSONObject.toJSONString(serviceInstance);
        JSONObject jsonObject = JSONObject.parseObject(json);
        JSONObject metadata = jsonObject.getJSONObject("metadata");
        if (metadata == null) {
            metadata = new JSONObject();
        }
        String instanceId = jsonObject.getString("instanceId");
        String ip = jsonObject.getString("ip");
        Integer port = jsonObject.getInteger("port");
        //元数据里面的值
        String serviceId = metadata.getString(ContextConstants.METADATA_SERVICE_ID);
        //实例id
        if (StrUtil.isBlank(serviceId)) {
            serviceId = instanceId;
        }
        //返回port加端口
        if (StrUtil.isBlank(serviceId)) {
            serviceId = ip + ":" + port;
        }
        return serviceId;
    }
}
